package Checkers;
import java.util.Arrays;

public class GenePool
{
    private final int numPolys=14; //even number = number of ai's
    private final int initialMutations = 3;
    private DNA[] allPolys;
    private DNA legend; //oldest one to have ever lived (just in case we need to resurrect him)
    private String dnaVar,convergence; //records difference between generations
    private String dnaMean;
//    private DNA[] oldPolys;
    
    public GenePool()
    {
        convergence="Convergence Factor Over Generations: "; //approaches 0 = very good
        legend=new DNA();
        allPolys=new DNA[numPolys];
        
        zeroAllPolys();
        
        for(int i=0;i<initialMutations;i++)
            mutateAllPolys();
        resetScores();
    }
    
    public GenePool(int[] seed,int[] variance) //initialize all DNA to seed instead of poly0
    {
        convergence="Convergence Factor Over Generations: ";
        legend=new DNA();
        allPolys=new DNA[numPolys];
        
        initAllPolys(seed);
        
        for(int m=0;m<initialMutations;m++)
        {
            for(int i=0;i<allPolys.length;i++)
            {
                allPolys[i].mutate(variance);
            }
        }
        resetScores();
    }
    
    public int size()
    {
        return numPolys;
    }
    
    public void zeroAllPolys()
    {
        for(int i=0;i<allPolys.length;i++)
        {
            allPolys[i]=new DNA();
        }
    }

    public void initAllPolys(int[] seed)
    {
        for(int i=0;i<allPolys.length;i++)
        {
            allPolys[i]=new DNA();
            allPolys[i].setPoly(seed);
        }
    }

    public void mutateAllPolys()
    {
        for(int i=0;i<allPolys.length;i++)
        {
            allPolys[i].mutate();
        }
    }
    
    public void spawnChild(int parent,int child)
    {
        allPolys[child].setPoly(allPolys[parent].getPoly());
        allPolys[child].revive();
        allPolys[child].mutate();
    }
    
    public void resetScores() {
        for(int i=0;i<allPolys.length;i++)
        {
            allPolys[i].resetScore();
        }
    }
/*    
    public void resetScores()
    {
        int scores[] = new int[numPolys];
        scores[0] = getScore(0);
        int max = scores[0];
        for (int i=1; i<wins.length; i++) {
            scores[i] = getScore(i);
            if (scores[i] > max)
                max = scores[i];
        }
        for (int i=0; i<wins.length; i++) {
            wins[i] = 0;
            if (scores[i] == max)       // give it a boost
                wins[i] = 1;
            draws[i] = 0;
            losses[i] = 0;
        }
    }
*/    
    public void addWin(int index)
    {
        allPolys[index].wins++;
    }

    public void addDraw(int index)
    {
        allPolys[index].draws++;
    }

    public void addLoss(int index)
    {
        allPolys[index].losses++;
    }
    
    public int[] getPoly(int index)
    {
        return allPolys[index].getPoly();
    }

    public String massExtinction() //returns stats
    {
//        oldPolys = allPolys.clone();
        
        String oldDNA=allStats();
        String survived="Survivors: ";
        String died=    "     Dead: ";
/*        
        int scores[] = new int[numPolys];
        for (int i =0; i<numPolys; i++) {
            scores[i] = getScore(i);
        }
        Arrays.sort(scores);
        for (int i =0; i<numPolys/2; i++) {
            died+="P"+i+",Score="+scores[i]+" | ";
            wins[i]=-1;
            allPolys[i]=null;           
        }
        for (int i=numPolys-1; i>= numPolys/2; i--) {
            survived+="P"+i+",Score="+scores[i]+" | ";
            age[i]++;
            if(age[i]>oldest)
            {
                oldest=age[i];
                legend=allPolys[i].clone();
            }
            spawnChild(i, i-numPolys/2);
        }
        resetScores();
*/
        //kill off bottom half
        int index,score;
        for(int i=0;i<numPolys/2;i++)
        {
            index=getWeakestLink();
            died+="P"+index+",Score="+allPolys[index].getScore()+" | ";
            allPolys[index].die();
        }

        updateConvergence();
        
        //each of top half makes a slightly mutated clone
        for(int i=0;i<allPolys.length;i++)
        {
            //found a survivor
            if(!allPolys[i].isDead() && allPolys[i].survivor)
            {
                survived+="P"+i+",Score="+allPolys[i].getScore()+" | ";
                allPolys[i].age++;
                if(allPolys[i].age>legend.age)
                {
                    legend=new DNA(allPolys[i]);
                }
                
                //search for empty slot to spawn child (should always find)
                for(int j=0;j<allPolys.length;j++)
                {
                    if(allPolys[j].isDead())
                    {
                        spawnChild(i,j);
//                        System.out.println("Child spawned: "+i+" --> "+j);
                        break;
                    }
                }
            }
        }
        
        resetScores();
        
        return "\n----Mass Extinction Event Occurs----\n"+"Old DNA:\n"+oldDNA+survived +"\n"+died+"\n"+"New DNA:\n"+allStats()+legendStats()+dnaMean+dnaVar+convergence+"\n";
    }
    
    private int getWeakestLink()
    {
        int index=0;
        int minVal=9999999;
        int score = 0;
        for(int i=0;i<allPolys.length;i++)
        {
            if(!allPolys[i].isDead())
            {
                score = allPolys[i].getScore();
                if(score<minVal || score==minVal && Math.random()<0.3)//randomize
                {
                    index=i;
                    minVal=score;
                }
            }
        }
        return index;
    }
    
    public String legendStats()
    {
        return legend.stats("X")+"\n";
    }
    
    private void updateConvergence()
    {
        double sum=0;
        dnaVar= "DNA Variance: ";
        dnaMean="    DNA Mean: ";
        int var,mean;
        for(int i=0;i<allPolys[0].size();i++)
        {
            var = variance(allPolys,i);
            mean = average(allPolys,i);
            dnaVar+=var+", ";
            dnaMean+=mean+", ";
            if(i!=0)//don't count weight 0 because its always the same
            {
                sum+=Math.abs(var);
            }
        }
        dnaVar+="\n";
        dnaMean+="\n";
        int cFactor = (int)(sum/((double)allPolys[0].size()));
//        convergence+=cFactor+", ";
        convergence = "Average Variance = "+cFactor;
    }
    
    private int average(DNA[] polys, int w)
    {
        int sum=0;
        for(int i=0;i<polys.length;i++)
        {
            if(!polys[i].isDead())
            {
                sum+=polys[i].getWeight(w);
            }
        }
        return (int)((double)sum/(numPolys/2));
    }
    
    private int variance(DNA[] polys, int w)//w=weight number, variance = difference between max/min value of weight over all 10 players
    {
        int min=9999999,max=-9999999,test;
        for(int i=0;i<polys.length;i++)
        {
            if(!polys[i].isDead())
            {
                test=polys[i].getWeight(w);
                if(test<min)
                    min=test;
                if(test>max)
                    max=test;
            }
        }
        return max-min;
    }
    
    
    public String allStats()
    {
        String s="";
        for(int i=0;i<allPolys.length;i++)
        {
            s+=allPolys[i].stats(""+i)+"\n";
        }
        return s;
    }
}
